package cn.virens.common.apifox.web;

import cn.virens.common.mybatis.entity.param.PageParam;
import cn.virens.common.util.core.network.RequestUtil;
import cn.virens.common.util.core.network.SessionUtil;
import cn.virens.common.util.exception.APIException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.dromara.hutool.core.text.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ApplicationObjectSupport;

import java.util.function.Supplier;

/**
 * 通用控制器
 *
 * @author virens
 */
public class BaseController extends ApplicationObjectSupport {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    protected String baseTemplateUrl = "";

    /**
     * @param url 模板根路径
     */
    protected BaseController(String url) throws APIException {
        if (url != null && !StrUtil.endWith(url, '/')) {
            this.baseTemplateUrl = url + "/";
        } else {
            this.baseTemplateUrl = url;
        }
    }

    /**
     * 返回模板地址
     *
     * @param url 模板路径
     * @return 模板地址
     */
    protected final String returnUrl(String url) throws APIException {
        return baseTemplateUrl + StrUtil.defaultIfEmpty(url, "index");
    }

    /**
     * 页面重定向
     *
     * @param url 重定向地址
     * @return 重定向地址
     */
    protected final String redirectUrl(String url) throws APIException {
        if (url != null && !StrUtil.endWith(url, ".jspx")) {
            return "redirect:" + url + ".jspx";
        } else {
            return "redirect:" + url;
        }
    }

    /**
     * 请求转发
     *
     * @param url 转发地址
     * @return 转发地址
     */
    protected final String forwardUrl(String url) {
        return "forward:" + url;
    }

    /**
     * 获取session值
     *
     * @param request HttpServletRequest实例
     * @param name    session名称
     * @return Object
     */
    protected final Object getAttribute(HttpServletRequest request, String name) {
        return SessionUtil.useSession(request, false, (session) -> {
            return session != null ? session.getAttribute(name) : null;
        });
    }

    /**
     * 获取session值
     *
     * @param <T>     返回类型
     * @param request HttpServletRequest实例
     * @param name    session名称
     * @param clazz   session值类型
     * @return Object
     */
    protected final <T> T getAttribute(HttpServletRequest request, String name, Class<T> clazz) {
        return SessionUtil.useSession(request, false, session -> getAttribute(session, name, clazz));
    }

    /**
     * 获取session值
     *
     * @param <T>     返回类型
     * @param session Session管理器
     * @param name    session名称
     * @param clazz   session值类型
     * @return Object
     */
    @SuppressWarnings("unchecked")
    protected final <T> T getAttribute(HttpSession session, String name, Class<T> clazz) {
        if (session != null && name != null && clazz != null) {
            Object obj = session.getAttribute(name);

            if (clazz == String.class && obj != null) {
                return (T) String.valueOf(obj);
            } else if (isAssignableFrom(obj, clazz)) {
                return (T) obj;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    private static boolean isAssignableFrom(Object obj, Class<?> clazz) throws APIException {
        return clazz != null && obj != null && clazz.isAssignableFrom(obj.getClass());
    }

    /**
     * 获取session值，如果不存在则从callable加载，并存入session
     *
     * @param <T>      返回类型
     * @param request  HttpServletRequest实例
     * @param name     session键
     * @param clazz    session键类型
     * @param supplier 不存在加载
     * @return Object
     */
    protected final <T> T getAttribute(HttpServletRequest request, String name, Class<T> clazz, Supplier<T> supplier) {
        return SessionUtil.useSession(request, false, (session) -> {
            if (session == null || clazz == null) return null;

            // 获取session值
            T obj = getAttribute(session, name, clazz);

            // 如果session值为空，则从supplier中加载
            if (obj == null && supplier != null) {
                obj = supplier.get();

                // 如果加载的session值不为空，存入session中
                if (obj != null) {
                    session.setAttribute(name, obj);
                }
            }

            return obj;
        });
    }

    /**
     * 存入session值
     *
     * @param <T>     返回类型
     * @param request HttpServletRequest实例
     * @param name    session键
     * @param value   session值
     * @return Object
     */
    protected final <T> T setAttribute(HttpServletRequest request, String name, T value) {
        return SessionUtil.useSession(request, false, (session) -> {
            if (session != null && name != null && value != null) {
                session.setAttribute(name, value);
            } else if (session != null && name != null) {
                session.removeAttribute(name);
            } else {
                return null;
            }

            return value;
        });
    }

    /**
     * 获取分页请求参数
     */
    protected PageParam getParam(HttpServletRequest request) throws APIException {
        Integer pageSize = RequestUtil.getValueInt(request, "limit", 10);
        Integer pageNum = RequestUtil.getValueInt(request, "page", 1);

        PageParam pageParam = new PageParam();
        pageParam.setPageSize(pageSize);
        pageParam.setPageNum(pageNum);

        return pageParam;
    }
}
